/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package sheep.JUNG.utils;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ConcurrentModificationException;
import java.util.Iterator;

import javax.swing.JComponent;


import edu.uci.ics.jung.graph.Edge;
import edu.uci.ics.jung.graph.Vertex;
import edu.uci.ics.jung.visualization.Layout;
import edu.uci.ics.jung.visualization.PickSupport;
import edu.uci.ics.jung.visualization.PickedState;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.VisualizationViewer.Paintable;
import edu.uci.ics.jung.visualization.control.AbstractGraphMousePlugin;

//////////////////////////////////////////////////////////////////////////////////////
import sheep.controller.Workspace;
import sheep.model.Task;
import sheep.view.VisualProjectPanel;

/**
 * @author geek
 *
 */
public class OurPickingGraphMousePlugin extends AbstractGraphMousePlugin
    implements MouseListener, MouseMotionListener {

    //////////////////////////////////////////////////////////////////////////////////////

    /**
     * 
     */
    protected Vertex vertex;
    protected Edge edge;
    protected double offsetx;
    protected double offsety;
    protected boolean locked;
    protected int addToSelectionModifiers;
    protected Rectangle2D rect = new Rectangle2D.Float();
    protected Paintable lensPaintable;
    protected Color lensColor = Color.cyan;
    Workspace workSpace;
    
    //////////////////////////////////////////////////////////////////////////////////////

	/**
	 * @param projet
	 * @param pref
	 */
	public OurPickingGraphMousePlugin(Workspace workSpace) {
	    this(InputEvent.BUTTON1_MASK, InputEvent.BUTTON1_MASK | InputEvent.SHIFT_MASK,
	    		workSpace);
	}
	
    //////////////////////////////////////////////////////////////////////////////////////

    /**
     * @param selectionModifiers
     * @param addToSelectionModifiers
     * @param projet
     * @param pref
     */
    public OurPickingGraphMousePlugin(int selectionModifiers, int addToSelectionModifiers,
    				Workspace workSpace) {
        super(selectionModifiers);
        this.workSpace = workSpace;
        this.addToSelectionModifiers = addToSelectionModifiers;
        this.lensPaintable = new LensPaintable();
        this.cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
    }
    
    //////////////////////////////////////////////////////////////////////////////////////
  
    /**
     * @return
     */
    public Color getLensColor() {
        return lensColor;
    }

    //////////////////////////////////////////////////////////////////////////////////////
    
    /**
     * @param lensColor
     */
    public void setLensColor(Color lensColor) {
        this.lensColor = lensColor;
    }
 
    //////////////////////////////////////////////////////////////////////////////////////

    /**
     * @author geek
     *
     */
    class LensPaintable implements Paintable {

        public void paint(Graphics g) {
            Color oldColor = g.getColor();
            g.setColor(lensColor);
            ((Graphics2D)g).draw(rect);
            g.setColor(oldColor);
        }

        public boolean useTransform() {
            return false;
        }
    }

    //////////////////////////////////////////////////////////////////////////////////////

    /* (non-Javadoc)
     * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
     */
    public void mousePressed(MouseEvent e) {
        down = e.getPoint();
        VisualizationViewer vv = (VisualizationViewer)e.getSource();
        PickSupport pickSupport = vv.getPickSupport();
        PickedState pickedState = vv.getPickedState();
        if(pickSupport != null && pickedState != null) {
            Layout layout = vv.getGraphLayout();
            if(e.getModifiers() == modifiers) {
                vv.addPostRenderPaintable(lensPaintable);
                rect.setFrameFromDiagonal(down,down);
                // p is the screen point for the mouse event
                Point2D p = e.getPoint();
                // take away the view transform
                Point2D ip = vv.inverseViewTransform(p);
                
                vertex = pickSupport.getVertex(ip.getX(), ip.getY());
                if(vertex != null) {
                    if(pickedState.isPicked(vertex) == false) {
                        pickedState.clearPickedVertices();
                        pickedState.pick(vertex, true);
                        Task task =(Task) vertex.getUserDatum("Key");
                        this.workSpace.setSelectedTask(task);
                        //this.workSpace.setCurrentTask(task);
                        if(e.getClickCount()==2){
                          if(!task.getName().equals("start") && !task.getName().equals("end"))
                            VisualProjectPanel.showDlg();
                        }
                    }
                    Point2D q = layout.getLocation(vertex);
                    Point2D gp = vv.inverseLayoutTransform(ip);
                    offsetx = (float) (gp.getX()-q.getX());
                    offsety = (float) (gp.getY()-q.getY());
                } else if((edge = pickSupport.getEdge(ip.getX(), ip.getY())) != null) {
                    pickedState.clearPickedEdges();
                    pickedState.pick(edge, true);
                    //this.projet.setSelectedEdge(edge);
                	//((OurEdge)edge).setSelected(edge);
                } else {
                    pickedState.clearPickedEdges();
                    pickedState.clearPickedVertices();
                }
            } else if(e.getModifiers() == addToSelectionModifiers) {
                vv.addPostRenderPaintable(lensPaintable);
                rect.setFrameFromDiagonal(down,down);
                Point2D p = e.getPoint();
                // remove view transform
                Point2D ip = vv.inverseViewTransform(p);
                vertex = pickSupport.getVertex(ip.getX(), ip.getY());
                if(vertex != null) {
                    boolean wasThere = pickedState.pick(vertex, !pickedState.isPicked(vertex));
                    if(wasThere)
                        vertex = null;
                    else {
                        Point2D q = layout.getLocation(vertex);
                        Point2D gp = vv.inverseLayoutTransform(ip);
                        offsetx = (float) (gp.getX()-q.getX());
                        offsety = (float) (gp.getY()-q.getY());
                    }
                    if (vertex != null){
                    Task task =(Task) vertex.getUserDatum("Key");
                    this.workSpace.setSelectedTask(task);
                    //this.workSpace.setCurrentTask(task);
                    if(e.getClickCount()==2){
                      if(!task.getName().equals("start") && !task.getName().equals("end"))
                          VisualProjectPanel.showDlg();
                     }
                    }
                    //task.setSelected();

                } else if((edge = pickSupport.getEdge(ip.getX(), ip.getY())) != null) {
                    pickedState.pick(edge, !pickedState.isPicked(edge));
                    //this.projet.setSelectedEdge(edge);
                	//((OurEdge)edge).setSelected(edge);
                }
            }
        }
        if(vertex != null) e.consume();
    }

    //////////////////////////////////////////////////////////////////////////////////////

    /* (non-Javadoc)
     * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
     */
    public void mouseReleased(MouseEvent e) {
        VisualizationViewer vv = (VisualizationViewer)e.getSource();
        if(e.getModifiers() == modifiers) {
            if(down != null) {
                Point2D out = e.getPoint();
                if(vertex == null && heyThatsTooClose(down, out, 5) == false) 
                    pickContainedVertices(vv, true);
            }
        } else if(e.getModifiers() == this.addToSelectionModifiers) {
            if(down != null) {
                Point2D out = e.getPoint();
                if(vertex == null && heyThatsTooClose(down,out,5) == false) 
                    pickContainedVertices(vv, false);
            }
        }
        if (vertex!=null){
        	Layout layout = vv.getGraphLayout();
        	Point2D q = layout.getLocation(vertex);
        	//((Task)vertex.getUserDatum("Key")).setVertexPos(q);
        	//this.this.workSpace.getCurrentProject().getGraph().getVertexLocations().setLocation(vertex, q);
            Task task =(Task) vertex.getUserDatum("Key");
            task.setLocation(q);
            task.setAutoLocation(q);
            System.out.println("Position" + q.toString());
            this.workSpace.setSelectedTask(task);
            //this.workSpace.setCurrentTask(task);
            if(e.getClickCount()==2){
              if(!task.getName().equals("start") && !task.getName().equals("end"))
              VisualProjectPanel.showDlg();
            }          
            //task.setSelected();

        }
        down = null;
        vertex = null;
        edge = null;
        rect.setFrame(0,0,0,0);
        vv.removePostRenderPaintable(lensPaintable);
    }
    
    //////////////////////////////////////////////////////////////////////////////////////

    /* (non-Javadoc)
     * @see java.awt.event.MouseMotionListener#mouseDragged(java.awt.event.MouseEvent)
     */
    public void mouseDragged(MouseEvent e) {
        if(locked == false) {
            VisualizationViewer vv = (VisualizationViewer)e.getSource();
            if(vertex != null) {
                Point p = e.getPoint();
                Point2D graphPoint = vv.inverseTransform(p);
                Point2D graphDown = vv.inverseTransform(down);
                Layout layout = vv.getGraphLayout();
                double dx = graphPoint.getX()-graphDown.getX();
                double dy = graphPoint.getY()-graphDown.getY();
                PickedState ps = vv.getPickedState();
                
                for(Iterator<?> iterator=ps.getPickedVertices().iterator(); iterator.hasNext(); ) {
                    Vertex v = (Vertex)iterator.next();
                    Point2D vp = layout.getLocation(v);
                    layout.forceMove(v, vp.getX()+dx, vp.getY()+dy);
                }
                down = p;
            } else {
                Point2D out = e.getPoint();
                if(e.getModifiers() == this.addToSelectionModifiers ||
                        e.getModifiers() == modifiers) 
                    rect.setFrameFromDiagonal(down,out);
            }
            if(vertex != null) e.consume();
        }
    }
    
    //////////////////////////////////////////////////////////////////////////////////////

    /**
     * @param p
     * @param q
     * @param min
     * @return
     */
    private boolean heyThatsTooClose(Point2D p, Point2D q, double min) {
        return Math.abs(p.getX()-q.getX()) < min &&
                Math.abs(p.getY()-q.getY()) < min;
    }
    
    //////////////////////////////////////////////////////////////////////////////////////

    /**
     * @param vv
     * @param clear
     */
    protected void pickContainedVertices(VisualizationViewer vv, boolean clear) {
        
        Layout layout = vv.getGraphLayout();
        PickedState pickedState = vv.getPickedState();
        if(pickedState != null) {
            if(clear) 
                pickedState.clearPickedVertices();
            while(true) 
                try {
                    for (Iterator<?> iter=layout.getGraph().getVertices().iterator(); iter.hasNext();  ) {
                        Vertex v = (Vertex) iter.next();
                        if(rect.contains(vv.transform(layout.getLocation(v)))) 
                            pickedState.pick(v, true);
                    }
                    break;
                } catch(ConcurrentModificationException cme) {}
        }
    }

    //////////////////////////////////////////////////////////////////////////////////////

    /* (non-Javadoc)
     * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
     */
    public void mouseClicked(MouseEvent e) {}
    
    //////////////////////////////////////////////////////////////////////////////////////
    
    /* (non-Javadoc)
     * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent)
     */
    public void mouseEntered(MouseEvent e) {
        JComponent c = (JComponent)e.getSource();
        c.setCursor(cursor);
    }
    //////////////////////////////////////////////////////////////////////////////////////
    
    /* (non-Javadoc)
     * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent)
     */
    public void mouseExited(MouseEvent e) {
        JComponent c = (JComponent)e.getSource();
        c.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
    }
    //////////////////////////////////////////////////////////////////////////////////////
    
    /* (non-Javadoc)
     * @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent)
     */
    public void mouseMoved(MouseEvent e) {}
    
    //////////////////////////////////////////////////////////////////////////////////////
    
    /**
     * @return
     */
    public boolean isLocked() {
        return locked;
    }
    
    //////////////////////////////////////////////////////////////////////////////////////

    /**
     * @param locked
     */
    public void setLocked(boolean locked) {
        this.locked = locked;
    }	
    
    //////////////////////////////////////////////////////////////////////////////////////

}

//////////////////////////////////////////////////////////////////////////////////////

